// Copyright (c) 2023 CHANGLEI. All rights reserved.

import 'dart:collection';

import 'package:arith/src/arith.dart';

const _escapeSpecial = r'`([^`]+?)`';
final _escapeRegExp = RegExp(r'(\.|\*|\+|-|\?|\||\[|\]|\(|\)|\{|\}|\\|\^|\$|\\b|\\w|\\s|\\d)');

final _operator1Chars = _join(Operator1.values.map((e) => e.toString()));
final _operator2Chars = _join(Operator2.values.map((e) => e.toString()));
final _left = Curve.left.toString().escape;
final _right = Curve.right.toString().escape;
final _variable = '(?:($_escapeSpecial)|(((?!(?:$_left|$_right|$_operator1Chars|$_operator2Chars|`)).)+))';

int _compare(String a, String b) => b.length.compareTo(a.length);

String _join(Iterable<String> values) => (values.toList()..sort(_compare)).map((e) => e.escape).join(r'|');

final _normativeRegExp = RegExp('($_escapeSpecial)|\\s+');
final _tightenUpRegExp = RegExp('(,\\s)|($_escapeSpecial)|\\s+');
final _escapeSpecialRegExp = RegExp(_escapeSpecial);

/// Created by changlei on 2023/6/21.
///
/// 解析公式参数
final class Parser {
  /// 解析公式参数
  Parser(String expression, this._callables) : _expression = _normative(expression);

  final String _expression;

  /// 自定义函数
  final Set<Callable>? _callables;

  /// 子公式
  late final String _subexpression = _recursive(_parseCurves(_expression) - 1);

  /// 函数名称集
  late final _symbolChars = _join([...BuiltInMath.values, ...?_callables].map((e) => _escapeSpecial(e.symbol)));

  /// 匹配[Factor]的正则表达式
  late final _factorRegExp = RegExp(
    <String>[
      '($_left(?<expression>($_subexpression)*?)$_right)',
      '(?<symbol>((?:$_symbolChars)|`(?:$_symbolChars)`)(?=$_left($_subexpression)*?$_right))',
      '(?<variable>$_variable)',
      '(?<!(?:$_variable|$_right))(?<operator1>(?:$_operator1Chars))(?=(?:$_left|$_variable|$_operator1Chars))',
      '(?<operator2>(?:$_operator2Chars))',
      '(?<curve>(?:$_left|$_right))',
    ].join(r'|'),
  );

  /// 解析公式
  Expression parse([String? expression]) {
    expression ??= _tightenUp(_expression);
    final matches = Queue.of(allMatches(expression));
    final factors = <Factor>[];
    final length = expression.length;
    for (var index = 0; index < length;) {
      final next = matches.firstOrNull?.start ?? length;
      if (index >= next) {
        final match = matches.removeFirst();
        factors.addAll(_parseFactors(match, this));
        index = match.end;
      } else {
        final end = _expression.indexOf(expression.substring(index, next));
        throw ArithError.character(_expression, end, next + end - index);
      }
    }
    return Expression(factors);
  }

  /// 匹配
  Iterable<RegExpMatch> allMatches(String expression) {
    return _factorRegExp.allMatches(expression);
  }

  /// 解析自定义函数
  Math mathOf(String symbol) {
    return _callables?.maybeOf(_escapeSpecial(symbol)) ?? Math.of(symbol);
  }

  /// 去除公式中的多余的空格
  static String _normative(String expression) {
    return expression.replaceAllMapped(_normativeRegExp, (match) {
      return match.group(1) ?? ' ';
    });
  }

  /// 去除公式中的空格
  static String _tightenUp(String expression) {
    return expression.replaceAllMapped(_tightenUpRegExp, (match) {
      final group1 = match.group(1);
      final group2 = match.group(2);
      return group1 ?? group2 ?? '';
    });
  }

  /// 对变量转义
  static String _escapeSpecial(String variable) {
    return variable.replaceAllMapped(_escapeSpecialRegExp, (match) {
      return match.group(1) ?? match.input;
    });
  }

  /// 解析变量
  static Variables variablesOf(String variable) {
    return Variable1.of(_escapeSpecial(variable));
  }
}

int _parseCurves(String expression) {
  int maxDepth = 0;
  int depth = 0;
  final indexes = <int>[];
  final length = expression.length;
  for (var index = 0; index < length; index++) {
    final char = expression[index];
    if (char == Curve.left.toString()) {
      depth++;
      indexes.add(index);
      if (depth > maxDepth) {
        maxDepth = depth;
      }
    } else if (char == Curve.right.toString()) {
      depth--;
      if (depth < 0) {
        indexes.add(index);
      } else {
        indexes.removeLast();
      }
    }
  }
  if (depth == 0) {
    return maxDepth;
  }
  throw ArithError.curve(expression, indexes.first, indexes.last + 1, depth);
}

String _recursive(int maxDepth) {
  if (maxDepth <= 0) {
    return r'.';
  }
  final center = '(((?!(?:$_left|$_right)).)+)';
  final leading = '.*?(?:$center?|';
  const trailing = r')*?';
  final buffer = <String>['$_left.*?$center*?$_right'];
  int depth = 0;
  try {
    void recursion() {
      buffer.insert(0, '$_left$leading');
      buffer.add('$trailing$_right');
      depth++;
      if (depth < maxDepth) {
        recursion();
      }
    }

    recursion();
  } catch (_) {}
  return '$leading${buffer.join()}$trailing';
}

Iterable<Factor> _parseFactors(RegExpMatch match, Parser parser) sync* {
  final expression = match.namedGroup('expression');
  final symbol = match.namedGroup('symbol');
  final variable = match.namedGroup('variable');
  final operator1 = match.namedGroup('operator1');
  final operator2 = match.namedGroup('operator2');
  final curve = match.namedGroup('curve');
  if (expression != null) {
    yield* Curve.wrap(Variables.of(expression, parser));
  }
  if (symbol != null) {
    yield parser.mathOf(symbol);
  }
  if (variable != null) {
    yield Parser.variablesOf(variable);
  }
  if (operator1 != null) {
    yield Operator1.of(operator1);
  }
  if (operator2 != null) {
    yield Operator2.of(operator2);
  }
  if (curve != null) {
    yield Curve.of(curve);
  }
}

extension on String {
  /// 转义字符
  String get escape => replaceAllMapped(_escapeRegExp, (match) => '\\${match[1]}');
}
